//  *@comments: 测试promise完整性插件：npm i promises-aplus-tests
//  *@comments: 命令行测试程序： npx promises-aplus-tests promise.js
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECT = 'REJECTED'

function resolvePromise(promise2, x, resolve, reject) {
    // console.log(x);
    // console.log(promise2);
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle dete'))
    }

    let called = false;

    if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
        try {
            let then = x.then;

            if (typeof then === 'function') {
                // 认定其为promise
                then.call(x,
                    (y) => {
                        if (called) return;
                        called = true;
                        // resolve(y);
                        resolvePromise(promise2, y, resolve, reject)
                    }, (r) => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                )
            } else {
                // 不是promise  是一个普通值
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
}

class MyPromise {
    constructor(excutor) {
        this.status = PENDING
        this.value = undefined
        this.reason = undefined

        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];


        const resolve = (value) => {
            if (this.status == PENDING) {
                // 转变状态
                this.status = FULFILLED
                this.value = value

                this.onFulfilledCallbacks.forEach(fn => fn());
            }
        }

        const reject = (reason) => {
            if (this.status === PENDING) {
                // 转变状态
                this.status = REJECT
                this.reason = reason
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }

        try {
            excutor(resolve, reject);
        } catch (e) {
            reject(e)
        }

    }

    // x 为 普通值 或 promise
    then(onFulfilled, onRejected) {
        // 不传的时候， 默认值
        onFulfilled = typeof onFulfilled === 'function'
            ? onFulfilled
            : value => value;

        onFulfilled = typeof onFulfilled === 'function'
            ? onFulfilled
            : reason => {
                throw reason
            }

        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            }

            if (this.status === REJECT) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            }

            if (this.status === PENDING) {
                // 订阅过程
                this.onFulfilledCallbacks.push(() => {
                    try {
                        let x = onFulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })

                this.onRejectedCallbacks.push(() => {
                    try {
                        let x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })

            }
        })


        return promise2;
    }

    // catch方法
    catch(errorCallback) {
        return this.then(null, errorCallback);
    }

    // finally方法
    finally(cb) {
        return this.then(
            value => MyPromise.resolve(cb())
                .then(
                    () => value
                ),
            reason => MyPromise.resolve(cb())
                .then(
                    () => {
                        throw reason
                    }
                )
        );
    }

    // 添加静态resolve方法
    static resolve(value) {
        // 如果参数是MyPromise实例，直接返回这个实例
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }

    // 添加静态reject方法
    static reject(value) {
        return new MyPromise((resolve, reject) => reject(value))
    }


    // all 方法
    static all(promises) {
        return new MyPromise(
            (resolve, reject) => {
                let fulfilledCount = 0
                const itemNum = promises.length
                const rets = Array.from({length: itemNum})
                promises.forEach(
                    (promise, index) => {
                        MyPromise.resolve(promise).then(result => {
                            fulfilledCount++;
                            rets[index] = result;
                            if (fulfilledCount === itemNum) {
                                resolve(rets);
                            }
                        }, reason => reject(reason));
                    }
                )
            }
        )
    }

    // race 方法
    static race(promises) {
        return new MyPromise(function (resolve, reject) {
            for (let i = 0; i < promises.length; i++) {
                Promise.resolve(promises[i]).then(
                    function (value) {
                        return resolve(value)
                    },
                    function (reason) {
                        return reject(reason)
                    })
            }
        })
    }
}

export default MyPromise;
